package com.kitty.game.boss.service;

import com.kitty.common.model.Pos;
import com.kitty.common.utils.SpringUtils;
import com.kitty.game.ServerService;
import com.kitty.game.boss.BossDataPool;
import com.kitty.game.boss.config.BossSet;
import com.kitty.game.boss.model.BossFightParam;
import com.kitty.game.boss.model.BossNpcParam;
import com.kitty.game.config.GameMap;
import com.kitty.game.config.MapBossPos;
import com.kitty.game.config.NPC;
import com.kitty.game.config.XinJun;
import com.kitty.game.enter.Position;
import com.kitty.game.enter.RespDisappear;
import com.kitty.game.fight.bean.Fight;
import com.kitty.game.fight.factory.FightFactory;
import com.kitty.game.fight.service.FightService;
import com.kitty.game.item.model.PointItem;
import com.kitty.game.item.service.PointItemService;
import com.kitty.game.map.MapDataPool;
import com.kitty.game.map.model.GroupMapParam;
import com.kitty.game.npc.NpcDataPool;
import com.kitty.game.npc.service.appreace.AppearanceHandler;
import com.kitty.game.pet.model.Pet;
import com.kitty.game.pet.service.PetService;
import com.kitty.game.role.message.RespAppear;
import com.kitty.game.role.message.RespUpdateAppearance;
import com.kitty.game.role.model.Role;
import com.kitty.game.role.service.RoleService;
import com.kitty.game.team.model.Team;
import com.kitty.game.utils.Const;
import com.kitty.listener.event.FightEndEvent;
import com.kitty.mina.cache.DataCache;
import com.kitty.mina.message.MessagePusher;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.json.Json;
import org.nutz.lang.util.NutMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
//import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

@Service
public class NewBossService {
    @Autowired
    Dao dao;
    @Autowired
    NewBossService newBossService;

    private Logger logger = LoggerFactory.getLogger(getClass());

    private static AtomicInteger atomicInteger =new AtomicInteger(1000000000);

    /**取生成的NPCID*/
    public synchronized int getTempNpcId(){
        return atomicInteger.getAndIncrement();
    }
    /**
     * 加载产品数据
     */
    public void loadProductData() {
        loadBossSet();
        loadMapBossPosSet();
        loadXingJun();
    }

    /**
     * 加载通天塔星君配置
     */
    private void loadXingJun() {
        List<XinJun> list = dao.query(XinJun.class, Cnd.NEW());
        Map<String, XinJun> xinJunMap = new HashMap<>(list.size());
        for (XinJun xinJun : list) {
            xinJunMap.put(xinJun.getName(), xinJun);
        }
        BossDataPool.name2XingJun = xinJunMap;
    }


    /**
     * 加载bossSet数据
     */
    private void loadBossSet() {
        List<BossSet> list = dao.query(BossSet.class, Cnd.NEW());
        Map<String, BossSet> bossSetMap = new HashMap<>(list.size());

        for (BossSet bossSet : list) {
            /**出现重复名字抛出异常*/
            if (bossSetMap.containsKey(bossSet.getName())) {
                throw new RuntimeException("name为" + bossSet.getName() + "的bossset出现重复");
            }

            bossSetMap.put(bossSet.getName(), bossSet);
        }

        BossDataPool.bossSetMap = bossSetMap;
    }

    /**
     * 加载MapBossPos数据
     */
    private void loadMapBossPosSet() {
        List<MapBossPos> list = dao.query(MapBossPos.class, Cnd.NEW());
        Map<Integer, MapBossPos> mapBossPosMap = new HashMap<>(list.size());

        for (MapBossPos mapBossPos : list) {
            /**出现重复mapId抛出异常*/
            if (mapBossPosMap.containsKey(mapBossPos.getMapId())) {
                throw new RuntimeException("mapId为" + mapBossPos.getMapId() + "的mapbosspos出现重复");
            }

            mapBossPosMap.put(mapBossPos.getMapId(), clearRepeatPoint(mapBossPos));
        }

        BossDataPool.mapBossPosMap = mapBossPosMap;
    }

    /**
     * 去掉刷新NPC的重复位置
     */
    private MapBossPos clearRepeatPoint(MapBossPos oldMapBossPos) {
        MapBossPos mapBossPos = new MapBossPos();
        List<Position> positions = new ArrayList<>();
        mapBossPos.setList(positions);
        mapBossPos.setMapId(oldMapBossPos.getMapId());
        mapBossPos.setId(oldMapBossPos.getId());
        GameMap gameMap = MapDataPool.id2GameMaps.get(oldMapBossPos.getMapId());
        for (Position position : oldMapBossPos.getList()) {
//            double aa = Math.sqrt(Math.abs((position.getX() - gameMap.getTelePortX()) * (position.getX() - gameMap.getTelePortX()) + (position.getY() - gameMap.getTelePortY()) * (position.getY() - gameMap.getTelePortY())));
//            if (aa <= 10){
//                logger.error("距离太近mapid={}=={}==pos=={}",gameMap.getId(),gameMap.getName(), Json.toJson(position, JsonFormat.compact()));
//                continue;
//            }
            if (positions.size() == 0) {
                positions.add(position);
            } else {
                boolean boo = true;
                for (Position temp : positions) {
                    double juli = Math.sqrt(Math.abs((position.getX() - temp.getX()) * (position.getX() - temp.getX()) + (position.getY() - temp.getY()) * (position.getY() - temp.getY())));
                    if (juli < 6) {
                        boo = false;
                        break;
                    }
                }
                if (boo) {
                    positions.add(position);
                }
            }
        }
//        logger.error("剩余位置=={}=={}",gameMap.getName(),positions.size());
        return mapBossPos;
    }

    /**
     * 根据名字获得BossSet产品数据
     */
    public BossSet getBossSet(String name) {
        return BossDataPool.bossSetMap.get(name);
    }

    /**
     * 根据mapId获得MapBossPos产品数据
     */
    public MapBossPos getMapBossPos(int mapId) {
        return BossDataPool.mapBossPosMap.get(mapId);
    }

    /**
     * 在MapBossPos中配置的位置中随机获得1个位置
     */
    public Position getRandomPosition(MapBossPos mapBossPos) {
        if (mapBossPos == null || mapBossPos.getList() == null || mapBossPos.getList().isEmpty()) {
            return null;
        }

        int index = ThreadLocalRandom.current().nextInt(mapBossPos.getList().size());
        return mapBossPos.getList().get(index);
    }

    /**获得所有MapBossPos的mapId的列表*/
    public List<Integer> getBossPosMapList() {
        return new ArrayList<>(BossDataPool.mapBossPosMap.keySet());
    }

    /**从所有MapBossPos中随机获得一个MapBossPos产品数据*/
    public MapBossPos getRandomMapBossPos() {
        List<Integer> bossPosMapList = getBossPosMapList();
        int index = ThreadLocalRandom.current().nextInt(bossPosMapList.size());
        Integer mapId = bossPosMapList.get(index);
        return getMapBossPos(mapId);
    }

    /**
     * 根据一些参数创建对应的NPC
     */
    public NPC createBossNpc(Role role, BossNpcParam bossNpcParam) {
        if (bossNpcParam == null) {
            logger.error("创建npc=={}",Json.toJson(bossNpcParam));
            return null;
        }

        NPC npc = new NPC();
        npc.setIcon(bossNpcParam.getNpcIcon());
        /**唯一id */
        npc.setId(getTempNpcId());
        npc.setX(bossNpcParam.getPosition().getX());
        npc.setY(bossNpcParam.getPosition().getY());
        npc.setFangxiang(bossNpcParam.getDirection());
        npc.setMapId(bossNpcParam.getMapId());
        npc.setCreateTime(System.currentTimeMillis());

        /**计算结束显示时间戳*/
        if (bossNpcParam.getShowTimeSec() > 0) {
            long now = System.currentTimeMillis();
            long end = now + (bossNpcParam.getShowTimeSec() * Const.SECOND);
            npc.setEndTime(end);
        }

        if (bossNpcParam.getContent() != null) {
            npc.setContent(bossNpcParam.getContent());
        }
        if (bossNpcParam.getContent1() != null) {
            npc.setContent1(bossNpcParam.getContent1());
        }

        npc.setName(bossNpcParam.getNpcName());
        npc.setBossSetName(bossNpcParam.getBossSetName());

        /**设置NPC类型*/
        npc.setType(bossNpcParam.getNpcType());
        npc.setfujia_type(bossNpcParam.getfujia_type());
        /**设置属于哪个玩家*/
        npc.setRoleUid(bossNpcParam.getRoleUid());
        npc.setLevel(bossNpcParam.getLevel());


        /**加入到缓存中*/
        addTaskNpc(npc);

        /**广播给npc所在地图的所有玩家*/
        broadcastNpcShow(new GroupMapParam(role), npc);
//        logger.error("创建npc=={}",Json.toJson(npc));
        SpringUtils.getBean(ServerService.class).getScheduledExecutorService().schedule(new Runnable() {
            @Override
            public void run() {
                newBossService.delTaskNpc(npc);
                newBossService.broadcastNpcHide(new GroupMapParam(role), npc);
//                logger.error("定时器删除npc=={}",Json.toJson(npc));
            }
        },15*60, TimeUnit.SECONDS);
        return npc;
    }

    //TODO 拷贝了之前的代码，后面看下是否需要优化

    /**
     * 把任务刷出的NPC添加到缓存
     */
    public void addTaskNpc(NPC npc) {
        Set<Integer> set = DataCache.TASK_MAP_NPC.computeIfAbsent(npc.getMapId(), k -> new HashSet<>());
        set.add(npc.getId());
        DataCache.TASK_NPCS.put(npc.getId(), npc);
    }

    //TODO 拷贝了之前的代码，后面看下是否需要优化

    /**
     * 把任务刷出的NPC从缓存删除
     */
    public void delTaskNpc(NPC npc) {
        DataCache.TASK_NPCS.remove(npc.getId());
        Set<Integer> set = DataCache.TASK_MAP_NPC.get(npc.getMapId());
        if (set != null) {
            set.remove(npc.getId());
        }
    }

    //TODO 拷贝了之前的代码，后面看下是否需要优化

    /**
     * 广播NPC显示
     */
    public void broadcastNpcShow(GroupMapParam groupMapParam, NPC npc) {
        if (npc == null || npc.isShow() == false) {
            return;
        }
        Set<Integer> roleIds = SpringUtils.getMapService().getRoleIds(groupMapParam, npc.getMapId());
        if (roleIds == null || roleIds.size() <= 0) {
            return;
        }
        RespAppear respAppear = new RespAppear();
        respAppear.setRoleId(npc.getId());
        respAppear.setStatus(npc.getIcon());
        respAppear.setPosX(npc.getX());
        respAppear.setPosY(npc.getY());
        respAppear.setType(Const.CHARATER_NPC);
        respAppear.setDir(npc.getFangxiang());
        respAppear.setRoleName(npc.getName());
        respAppear.setTitle(npc.getTitle());
        respAppear.setOrg_icon(npc.getIcon());
        respAppear.setIcon(npc.getIcon());
        respAppear.setPortrait(npc.getIcon());
        respAppear.setWeaponId(npc.getWuqiId());
        respAppear.setSuit_icon(npc.getTaozhuangId());
        respAppear.setSuit_light_effect(npc.getFaguangId());
        SpringUtils.getMirrorService().changeRespAppear(npc, respAppear);
        for (Integer roleId : roleIds) {
            Role tempRole = SpringUtils.getRoleService().getOnlinePlayer(roleId);
            if (tempRole == null || npc.isMatchPolar((byte) tempRole.getPolar()) == false) {continue;}
            MessagePusher.pushMessage(tempRole, respAppear);
            // 缓存一下当前地图的npcID
//            Set<Integer> npcSet = tempRole.getTempCache(Const.npcIdSet, null);
//            if (npcSet != null) {
//                npcSet.add(npc.getId());
//            }
        }

    }

    //TODO 拷贝了之前的代码，后面看下是否需要优化

    /**
     * 广播NPC隐藏
     */
    public void broadcastNpcHide(GroupMapParam groupMapParam, NPC npc) {
        Set<Integer> roleIds = SpringUtils.getMapService().getRoleIds(groupMapParam, npc.getMapId());
        if (roleIds == null || roleIds.size() <= 0) {
            return;
        }
        RespDisappear respDisappear = new RespDisappear();
        respDisappear.setType(Const.CHARATER_NPC);
        respDisappear.setId(npc.getId());
        for (Integer roleId : roleIds) {
            Role role =SpringUtils.getRoleService().getOnlinePlayer(roleId);
            MessagePusher.pushMessage(role, respDisappear);
        }
    }

    /**
     * 广播NPC更新
     */
    public void broadcastNpcUpdate(GroupMapParam groupMapParam, NPC npc) {
        if (npc == null || npc.isShow() == false) {
            return;
        }
        Set<Integer> roleIds = SpringUtils.getMapService().getRoleIds(groupMapParam, npc.getMapId());
        if (roleIds == null || roleIds.size() <= 0) {
            return;
        }
        RespUpdateAppearance respAppear = new RespUpdateAppearance();
        respAppear.setRoleId(npc.getId());
        respAppear.setStatus(npc.getIcon());
        respAppear.setPosX(npc.getX());
        respAppear.setPosY(npc.getY());
        respAppear.setType(Const.CHARATER_NPC);
        respAppear.setDir(npc.getFangxiang());
        respAppear.setRoleName(npc.getName());
        respAppear.setTitle(npc.getTitle());
        respAppear.setOrg_icon(npc.getIcon());
        respAppear.setIcon(npc.getIcon());
        respAppear.setPortrait(npc.getIcon());
        respAppear.setWeaponId(npc.getWuqiId());
        respAppear.setSuit_icon(npc.getTaozhuangId());
        respAppear.setSuit_light_effect(npc.getFaguangId());
        AppearanceHandler appearanceHandler = NpcDataPool.appearanceHandlers.get(npc.getId());
        if (appearanceHandler != null) {
            Role role = groupMapParam != null ? groupMapParam.getRole() : null;
            appearanceHandler.changeRespUpdateAppearance(role, npc, respAppear);
        }
        for (Integer roleId : roleIds) {
            Role tempRole = SpringUtils.getRoleService().getOnlinePlayer(roleId);
            if (tempRole == null || npc.isMatchPolar((byte) tempRole.getPolar()) == false) {continue;}
            MessagePusher.pushMessage(tempRole, respAppear);
        }
    }

    public Fight startFightToBoss(Role role, BossFightParam bossFightParam) {
        Team team = SpringUtils.getFightService().getRoleFightTeam(role);

        return sendBossTeam(team, role, bossFightParam);
    }

    /**
     * boss战斗
     *
     * @param team
     * @param role
     * @param
     */
    public Fight sendBossTeam(Team team, Role role, BossFightParam bossFightParam) {
        FightService fightService = SpringUtils.getBean(FightService.class);
        if (fightService.canFight(role, team.getList()) == false) {
            return null;
        }
        if (SpringUtils.getTeamService().isInTeamAndNotLeader(role)) {
            logger.warn("{}({})不是队长触发战斗", role.getUid(), role.getName());
            return null;
        }

        int type = bossFightParam.getFightType();
        Pos position = role.getPos();
        int mapId = position.getMapId();
        Fight battleground = FightFactory.getFightFactory(type).create(mapId, role, team, bossFightParam);

        battleground.start();

        return battleground;
    }

    /**
     * 战斗结束后给奖励
     */
    public void giveReward(Role role, FightEndEvent fightEndEvent, double rewardRate, int monsterLevel) {
        logger.info("============={}=============", monsterLevel);
        NutMap reward = fightEndEvent.getReward();
        int exp = (int) (role.getLevel() * reward.getInt("rewardExp", 0) * rewardRate);
        int daijinquan = (int) (reward.getInt("rewardDaijinquan", 0) * rewardRate);
        int daohang = (int) (reward.getInt("rewardDaohang", 0) * rewardRate);
        int qianneng = (int) (reward.getInt("rewardQianneng", 0) * rewardRate);
        int money = (int) (reward.getInt("rewardMoney", 0) * rewardRate);
        int petWuxue = (int) (reward.getInt("petRewardWuxue", 0) * rewardRate);

        PetService petService = SpringUtils.getBean(PetService.class);
        RoleService roleService = SpringUtils.getRoleService();
        PointItemService pointItemService = SpringUtils.getBean(PointItemService.class);
        int currPetId = role.getTempCache("fight_current_pet_id", 0);
        Pet pet = petService.getPetById(currPetId, role);
        if (pet != null) {
            if (pointItemService.isOpen(role, PointItem.CHONG_FENG_SAN) && pointItemService.subtractChongFengSan(role, 4)) {
                petWuxue = petWuxue * 2;
            }
            roleService.addPetMatiral(role, pet, petWuxue);
        }

        if (pointItemService.isOpen(role, PointItem.JI_JI_RU_LV_LING) && pointItemService.subtractJiJiRuLvLing(role, 1)) {
            int size = reward.getInt("size", 1);
            money = money / size * 10;
            daohang = daohang / size * 10;
            qianneng = qianneng / size * 10;
        }

        if (pointItemService.isOpen(role, PointItem.DOUBLE) && pointItemService.subtractDouble(role, 4)) {
            money = money * 2;
            daohang = daohang * 2;
            qianneng = qianneng * 2;
            exp = exp * 2;
        }

        roleService.addExp(role, exp, monsterLevel,currPetId);
        roleService.addVoucher(role, daijinquan);
        roleService.addTao(role, daohang);
        roleService.addMoney(role, money);
        roleService.addPot(role, qianneng);
        role.save();
    }

    /**
     * 战斗结束后给奖励
     */
    public void giveRewardShidao(Role role, FightEndEvent fightEndEvent, double rewardRate, int monsterLevel) {
        NutMap reward = fightEndEvent.getReward();
        int exp = 0;// (int) (role.getLevel() * reward.getInt("rewardExp", 0) * rewardRate);
        int daijinquan = (int) (reward.getInt("rewardDaijinquan", 0) * rewardRate);
        int daohang = (int) (reward.getInt("rewardDaohang", 0) * rewardRate);
        int qianneng = (int) (reward.getInt("rewardQianneng", 0) * rewardRate);
        int money = (int) (reward.getInt("rewardMoney", 0) * rewardRate);
        int petWuxue = (int) (reward.getInt("petRewardWuxue", 0) * rewardRate);

        PetService petService = SpringUtils.getBean(PetService.class);
        RoleService roleService = SpringUtils.getRoleService();
        PointItemService pointItemService = SpringUtils.getBean(PointItemService.class);
        int currPetId = role.getTempCache("fight_current_pet_id", 0);
        Pet pet = petService.getPetById(currPetId, role);
        if (pet != null) {
            if (pointItemService.isOpen(role, PointItem.CHONG_FENG_SAN) && pointItemService.subtractChongFengSan(role, 4)) {
                petWuxue = petWuxue * 2;
            }
            roleService.addPetMatiral(role, pet, petWuxue);
        }

        if (pointItemService.isOpen(role, PointItem.JI_JI_RU_LV_LING) && pointItemService.subtractJiJiRuLvLing(role, 1)) {
            int size = reward.getInt("size", 1);
            money = money / size * 10;
            daohang = daohang / size * 10;
            qianneng = qianneng / size * 10;
        }

        if (pointItemService.isOpen(role, PointItem.DOUBLE) && pointItemService.subtractDouble(role, 4)) {
            money = money * 2;
            daohang = daohang * 2;
            qianneng = qianneng * 2;
            exp = exp * 2;
        }

//        roleService.addExp(role, exp, monsterLevel,currPetId);
        roleService.addVoucher(role, daijinquan);
        roleService.addTao(role, daohang);
        roleService.addMoney(role, money);
        roleService.addPot(role, qianneng);
        role.save();
    }
}
